using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using  System.IO;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Web;

namespace Thinxoft.HttpLib
{
    
    /// <summary>
	/// Summary description for HttpResponse.
	/// </summary>
	public class HttpResponse : MarshalByRefObject,IHttpResponse
    {
        public enum ResponseCode : int
        {
            Ok = 200,
            InternalError = 500
        }
        
        
        byte[] buffer;
		NameValueCollection  headers;
		byte[] response;
		string mime, responseCode;
		
		HttpApplication serverInfo;
		StringBuilder writeBuffer;
		HttpCookies cookies;

		internal HttpResponse(HttpApplication server,  HttpCookies cookies)
		{
            this.serverInfo = server;
            this.response = Encoding.ASCII.GetBytes("");
			this.responseCode = "200 OK";
			this.mime = "text/html";
            headers = new NameValueCollection();
            writeBuffer =  new StringBuilder();
			this.cookies = cookies;			
		}

		internal HttpResponse(string response, string responseCode, HttpApplication server)
		{
            this.serverInfo = server;
            this.response = Encoding.ASCII.GetBytes(response);
			this.responseCode = responseCode;
			this.mime = "text/html";
            headers = new NameValueCollection();

        }

		internal HttpResponse(HttpResource resource,string responseCode, string  mimexmlfile, HttpApplication server)
		{
			this.serverInfo = server;
			this.responseCode = responseCode;
            headers = new NameValueCollection();

            this.mime = GetMimeType(resource.FileExtension);
            this.response = resource.Data;
        }

		/// <summary>
		/// write with params
		/// </summary>
		/// <param name="response"></param>
		/// <param name="args"></param>
		public void Write(string text)
		{
			writeBuffer.Append(text);
		}

		/// <summary>
		/// write with params
		/// </summary>
		/// <param name="response"></param>
		/// <param name="args"></param>
		public void Write(string text, params string[] args)
		{
			writeBuffer.AppendFormat(text,args);
		}

        public void Clear()
        {
            writeBuffer = new StringBuilder();
        }

		public void Redirect(string format, params string[] args)
		{
			string location = string.Format(format,args);
			AddHeader("Location",location);
			this.responseCode = "307";
			response = Encoding.ASCII.GetBytes("");
			
		}

		string GetMimeType(string extension)
		{
			MimeTypes mt = serverInfo.ApplicationSettings.ServerMimeTypes;
			return mt.FindMimeTypeForFileExtention(extension);
//			foreach(XmlNode mime in mimes.DocumentElement)
//			{
//				if(mime.Attributes["name"].Value == extension)
//				{
//					return mime.Attributes["type"].Value;
//				}
//			}
//			return "*/*";
		}

		/// <summary>
		/// adds http headeres to the response
		/// </summary>
		/// <param name="name"></param>
		/// <param name="value"></param>
		public void AddHeader(string name, string val)
		{
			headers.Add(name,val);
			
		}

		public void RemoveHeader(string name)
		{
			headers.Remove(name);
		}

		public HttpCookies Cookies
		{
			get{
				return this.cookies;
			}
		}

		public IHttpCookies ResponseCookies
		{
			get
			{
				return this.cookies;
			}
		}

		public int Length
		{
			get
			{
				return this.buffer.Length;
			}
		}

		/// <summary>
		/// calles  by Refresh to add extra header to the header list
		/// </summary>
		/// <returns></returns>
		string ProcessExtraHeaders()
		{
			StringBuilder sb = new StringBuilder();
			foreach(string header in headers)
			{
				sb.Append(header + ": " + headers[header] + "\n");
			}
			return sb.ToString();
		}

		/// <summary>
		/// refreshes the internal state of the data buffer to reflect changes  made to the response object
		/// this method is called by many of the other operations but it does no harm to call it again
		/// </summary>
		public void Flush() 
		{
			if(writeBuffer != null)
			{
				string text = writeBuffer.ToString();
				response = Encoding.ASCII.GetBytes(text);
			}

			if(cookies != null)
			{
				if(cookies.Count > 0)
				{
					StringBuilder temp = new StringBuilder();
					foreach(string cookie in cookies)
					{
						string cval =  cookies[cookie];
						temp.Append(cookie + "=" +cval + " ");
					}
					AddHeader("Set-Cookie",temp.ToString());
				}
			}

			List<byte> retVal = new List<byte>();
			String headerStr =  "HTTP/1.1 "+ responseCode +" \r\n" +
				"Allow: GET, POST, HEAD\n" +
				"MIME-Version: 1.0\n" +
				"Server: Xedus\n" +					 
				"Content-Type: " + mime + "\n" +  
				ProcessExtraHeaders() +
				"Content-Length: " + response.Length + 				
				"\n\n";

			//get bytes from string
			byte[] header = Encoding.ASCII.GetBytes(headerStr);

			

			//load into arraylist
			retVal.AddRange(header);			
			retVal.AddRange(response);		
			

			//convert arraylist to byte array and return
			this.buffer = retVal.ToArray();
			
		}//end method


        public static byte[] WriteResponse(string message, ResponseCode code)
        {
            String headerStr = "HTTP/1.1 " + (int)code  + " \r\n" +
                "Allow: GET, POST, HEAD\n" +
                "MIME-Version: 1.0\n" +
                "Server: Xedus\n" +
                "Content-Type: text/plain \n" +                
                "Content-Length: " + message.Length +
                "\n\n" + message;

            //get bytes from string
            byte[] response = Encoding.ASCII.GetBytes(headerStr);
            return response;

        }
        public static byte[] WriteHTMLResponse(string message, ResponseCode code)
        {
            String headerStr = "HTTP/1.1 " + (int)code + " \r\n" +
                "Allow: GET, POST, HEAD\n" +
                "MIME-Version: 1.0\n" +
                "Server: Xedus\n" +
                "Content-Type: text/html \n" +
                "Content-Length: " + message.Length +
                "\n\n" + message;

            //get bytes from string
            byte[] response = Encoding.ASCII.GetBytes(headerStr);
            return response;

        }

        /// <summary>
		/// 
		/// </summary>
		/// <param name="resp"></param>
		/// <returns></returns>
		public static explicit operator byte[](HttpResponse resp)
		{
			resp.Flush();
			return resp.buffer;
		}
	}
}
